package com.cloud.charts4a.chart.render;

import com.cloud.charts4a.data.AbstractChartData;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Paint.FontMetrics;

/**
 * ChartRender Business Object<p/>
 * 
 * @version
 * <ol>
 * 	<li>2010/07/09 CloudTu：First Release</li>
 * </ol>
 * 
 * @author Cloud Tu
 */
class ChartRenderBo {
	/**
	 * XY軸背景格線線條寬度
	 */
	private final float xyAxisBackgroundGridLineWidth;
	
	/**
	 * XY軸線條寬度
	 */
	private final float xyAxisLineWidth;
	
	/**
	 * 圖表內的資料線條寬度
	 */
	private final float dataSeriesLineWidth;
	
	/**
	 * 圖表內的資料折線點半徑大小
	 */
	public final float dataSeriesDotRadias;	
	
	/**
	 * XY軸標籤的字型大小
	 */
	private final float labelTextSize;	
	
	/**
	 * XY軸裡單位說明文字的字型大小
	 */
	private final float xyAxisUnitDescTextSize;	
	
	/**
	 * 圖例標籤的字型大小
	 */
	private final float legendTextSize;
	
	/**
	 * 圖表資料被點擊時，顯示出來的提示文字字型大小
	 */
	private final float tipTextSize;	
	
	/**
	 * 圖表內的資料折線點被點擊時，顯示出來提示文字的上下左右留白間格大小
	 */
	public final float tipTextPadding;
	
	/**
	 * 圖表內的資料折線點被點擊時，顯示出來提示文字背景區塊四個端點的圓角半徑大小
	 */
	public final float tipRectCornerRadius;		
	
	/**
	 * 所有文字(提示文字除外)的上下左右留白間格大小
	 */
	public final float textPadding;			
	
	/**
	 * Chart Business Object
	 * 
	 * @param oneDipToPixel	一單位dip(Density-independent pixel)轉換成Pixel後的值
	 */
	public ChartRenderBo(float oneDipToPixel){		
		xyAxisBackgroundGridLineWidth = 1 * oneDipToPixel;
		xyAxisLineWidth = 2 * oneDipToPixel;
		dataSeriesLineWidth = 2 * oneDipToPixel;	
		dataSeriesDotRadias = 4 * oneDipToPixel; 
		labelTextSize = 12 * oneDipToPixel;
		xyAxisUnitDescTextSize = 13 * oneDipToPixel;
		legendTextSize = 13 * oneDipToPixel;
		tipTextSize = 16 * oneDipToPixel;
		tipTextPadding = 5 * oneDipToPixel; 
		tipRectCornerRadius = 5 * oneDipToPixel;
		textPadding = 3 * oneDipToPixel;		
	}
	
	/**
	 * Calculate text width in canvas
	 * 
	 * @param text		Text String
	 * @param paint		Paint
	 * 
	 * @return	Text width pixels 
	 */
	public float calTextWidth(String text,Paint paint){
		return paint.measureText(text);
	}		
	
	/**
	 * Calculate text height in canvas
	 * 
	 * @param paint	Paint
	 * 
	 * @return	Text height pixels
	 */
	public float calTextHeight(Paint paint){
		FontMetrics fontMetrics = paint.getFontMetrics();
		return Math.abs(fontMetrics.ascent + fontMetrics.descent); 			
	}
	
	/**
	 * 產生X軸與Y軸上刻度標籤的 paint object
	 * 
	 * @return	X軸與Y軸上刻度標籤的 paint object
	 */
	public Paint createXYAxisLabelPaint(){	
		Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		paint.setColor(Color.WHITE);
		paint.setTextSize(labelTextSize);
		paint.setTextAlign(Paint.Align.CENTER);
		return paint;
	}			
	
	/**
	 * 產生X軸與Y軸裡單位說明文字的Paint object
	 * 
	 * @return	X軸與Y軸裡單位說明文字的Paint object
	 */	
	public Paint createXYAxisUnitDescPaint(){	
		Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		paint.setColor(Color.WHITE);
		paint.setTextSize(xyAxisUnitDescTextSize);
		paint.setTextAlign(Paint.Align.CENTER);
		return paint;
	}	
	
	/**
	 * 產生數據資料圖例的Paint object
	 * 
	 * @param color	Color
	 * 
	 * @return	數據資料圖例的Paint object
	 */
	public Paint createLegendPaint(int color){	
		Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		paint.setColor(color);
		paint.setTextSize(legendTextSize);
		paint.setTextAlign(Paint.Align.CENTER);
		return paint;
	}		
	
	/**
	 * 產生折線點被點擊時，提示文字所用到的Paint object
	 * 
	 * @return	折線點被點擊時，提示文字所用到的Paint object
	 */
	public Paint createTipTextPaint(){	
		Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		paint.setColor(Color.WHITE);
		paint.setTextSize(tipTextSize);
		paint.setTextAlign(Paint.Align.CENTER);
		return paint;
	}		
	
	/**
	 * 產生折線點被點擊時，提示文字背景框所用到的Paint object
	 * 
	 * @return	折線點被點擊時，提示文字背景框所用到的Paint object
	 */
	public Paint createTipBackgroundRectPaint(){	
		Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		paint.setStyle(Paint.Style.FILL);
		paint.setColor(Color.GRAY);
		return paint;
	}		
	
	/**
	 * 產生X軸與Y軸背景格線的Paint object
	 * 
	 * @return	X軸與Y軸背景格線的Paint object
	 */
	public Paint createXYAxisBackgroundGridPaint(){	
		Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		paint.setColor(Color.argb(80, 204, 204, 204));	
		paint.setStrokeWidth(xyAxisBackgroundGridLineWidth);
		return paint;
	}		
	
	/**
	 * 產生X軸與Y軸的Paint object
	 * 
	 * @return	X軸與Y軸的Paint object
	 */
	public Paint createXYAxisPaint(){	
		Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		paint.setColor(Color.WHITE);
		paint.setStrokeWidth(xyAxisLineWidth);
		return paint;
	}			
	
	/**
	 * Create data series line paint
	 * 
	 * @param color Color
	 * 
	 * @return data	series line paint
	 */
	public Paint createDataSeriesLinePaint(int color){	
		Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);		
		paint.setColor(color);
		paint.setStrokeWidth(dataSeriesLineWidth);
		return paint;
	}		
	
	/**
	 * Create Y-Axis range highlight rectangle paint
	 * 
	 * @param color	Color
	 * 
	 * @return	Y-Axis range highlight rectangle paint
	 */
	public Paint createYRangeHighLightRectPaint(int color){	
		return createDataSeriesLinePaint(color);
	}	
	
	/**
	 * Create data series dot paint
	 * 
	 * @param color Color
	 * 
	 * @return	data series dot paint
	 */
	public Paint createDataSeriesDotPaint(int color){	
		Paint dataSeriesDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		dataSeriesDotPaint.setColor(color);
		return dataSeriesDotPaint;
	}			
	
	/**
	 * Calculate xAxisLabel(or yAxisLabel) width pixels
	 * 
	 * @param	maxXAxisLabelOrMaxYAxisLabel	所有X軸(或Y軸)標籤裡的最大值 
	 * 
	 * @return	xAxisLabel(or yAxisLabel) width pixels
	 */
	public float calXAxisLabelOrYAxisLabelWidth(String maxXAxisLabelOrMaxYAxisLabel){
		return calTextWidth(maxXAxisLabelOrMaxYAxisLabel, createXYAxisLabelPaint());
	}		
	
	/**
	 * Calculate xAxisLabel(or yAxisLabel) height pixels
	 * 
	 * @param	xyAxisLabelPaint	xyAxisLabel paint
	 * 
	 * @return	xAxisLabel(or yAxisLabel) height pixels
	 */
	public float calXAxisLabelOrYAxisLabelHeight(Paint xyAxisLabelPaint){
		return calTextHeight(xyAxisLabelPaint);		
	}
	
	/**
	 * 計算X軸裡單位說明文字的字型高度大小為儿Pixel
	 * 
	 * @param isShowXUnitDesc		是否要顯示X軸的單位說明
	 * @param xAxisUnitDescPaint	X軸裡單位說明文字的Paint object
	 * 
	 * @return	X軸裡單位說明文字的字型高度大小為儿Pixel
	 */
	public float calXAxisUnitDescHeight(boolean isShowXUnitDesc,Paint xAxisUnitDescPaint){
		if(isShowXUnitDesc == true){
			return calTextHeight(xAxisUnitDescPaint);				
		}
		else{
			return 0;
		}	
	}	
	
	/**
	 * 計算Y軸裡單位說明文字的字型高度大小為儿Pixel
	 * 
	 * @param isShowYUnitDesc		是否要顯示Y軸的單位說明
	 * @param yAxisUnitDescPaint	Y軸裡單位說明文字的Paint object
	 * 
	 * @return	Y軸裡單位說明文字的字型高度大小為儿Pixel
	 */
	public float calYAxisUnitDescHeight(boolean isShowYUnitDesc,Paint yAxisUnitDescPaint){
		if(isShowYUnitDesc == true){
			return calTextHeight(yAxisUnitDescPaint);				
		}
		else{
			return 0;
		}	
	}		
	
	/**
	 * Calculate yAXisLabel width pixels with left and right padding
	 * 
	 * @param maxYAxisLabel		所有Y軸標籤裡的最大值
	 * @param yAxisLabelPaint	yAxisLabel paint
	 * 
	 * @return	yAXisLabel width pixels with left and right padding
	 */
	public float calYAxisLabelWidthWithLeftAndRightPad(String maxYAxisLabel,Paint yAxisLabelPaint){
		return calTextWidth(maxYAxisLabel, yAxisLabelPaint) + textPadding * 2;
	}
	
	
	/**
	 * Calculate xAxisLabel height pixels with top and bottom padding
	 * 
	 * @param xAxisLabelPaint	xAxisLabel paint
	 * 
	 * @return xAxisLabel height pixels with top and bottom padding
	 */
	public float calXAxisLabelHeightWithTopAndBottomPad(Paint xAxisLabelPaint){	
		return calXAxisLabelOrYAxisLabelHeight(xAxisLabelPaint) + textPadding * 2;
	}	
	
	/**
	 * 計算X軸裡單位說明文字的字型高度大小加了上下留白空間後為儿Pixel
	 * 
	 * @param isShowXUnitDesc		否要顯示X軸的單位說明
	 * @param xAxisUnitDescPaint 	X軸裡單位說明文字的Paint object
	 * 
	 * @return X軸裡單位說明文字的字型高度大小加了上下留白空間後為儿Pixel
	 */
	public float calXAxisUnitDescHeightWithTopAndBottomPad(boolean isShowXUnitDesc,Paint xAxisUnitDescPaint){	
		if(isShowXUnitDesc == true){
			return calXAxisUnitDescHeight(isShowXUnitDesc,xAxisUnitDescPaint) + textPadding * 2;			
		}
		else{
			return 0;
		}
	}		
	
	/**
	 * 計算Y軸裡單位說明文字的字型高度大小加了上下留白空間後為儿Pixel
	 * 
	 * @param isShowYUnitDesc		是否要顯示Y軸的單位說明
	 * @param yAxisUnitDescPaint	Y軸裡單位說明文字的Paint object
	 * 
	 * @return Y軸裡單位說明文字的字型高度大小加了上下留白空間後為儿Pixel
	 */
	public float calYAxisUnitDescHeightWithTopAndBottomPad(boolean isShowYUnitDesc,Paint yAxisUnitDescPaint){	
		if(isShowYUnitDesc == true){
			return calYAxisUnitDescHeight(isShowYUnitDesc,yAxisUnitDescPaint) + textPadding * 2;			
		}
		else{
			return 0;
		}
	}		
	
	/**
	 * Calculate specified legend width pixels with left and right padding
	 * 
	 * @param legend	Legend String
	 * 
	 * @return	legend width pixels with left and right padding
	 */
	public float calSpecifiedLegendWidthWithLeftAndRightPad(String legend){
		Paint legendPaint = createLegendPaint(Color.WHITE);
		return calTextWidth(legend, legendPaint) + textPadding * 2;
	}	
	
	/**
	 * Calculate one legend height pixels with top and bottom padding
	 * 
	 * @return legend height pixels with top and bottom padding
	 */
	public float calOneLegendHeightWithTopAndBottomPad(){	
		Paint legendPaint = createLegendPaint(Color.WHITE);
		return calTextHeight(legendPaint) + textPadding * 2;	
	}	
	
	/**
	 * Calculate total legends height pixels with top and bottom padding
	 * 
	 * @param isShowLegend	是否要顯示圖例
	 * @param legends		圖例標籤
	 * @param canvasWidth	Canvas width
	 * 
	 * @return	total legends height pixels with top and bottom padding
	 */
	public float calTotalLegendsHeightWithTopAndBottomPad(boolean isShowLegend,String[] legends,float canvasWidth){
		if(isShowLegend == true && legends != null){
			float totalWidthOfLegends = 0;		
			for (String legend : legends) {
				totalWidthOfLegends = totalWidthOfLegends + calSpecifiedLegendWidthWithLeftAndRightPad(legend);
			}
			
			float oneLegendHeightWithTopAndBottomPad = calOneLegendHeightWithTopAndBottomPad();
			if(canvasWidth >  totalWidthOfLegends){
				return oneLegendHeightWithTopAndBottomPad;	
			}
			else{
				int rate = (int)Math.ceil(totalWidthOfLegends / canvasWidth);
				return oneLegendHeightWithTopAndBottomPad * rate;
			}				
		}		
		else{
			return 0;
		}
	}			
	
	/**
	 * Calculate y-axis interval pixels of two yAxisLabel unit 
	 * 
	 * @param canvasWidth			Canvas width
	 * @param canvasHeight			Canvas Height
	 * @param yAxisLabelAmount		Y軸標籤總個數
	 * @param isShowXUnitDesc		是否要顯示X軸的單位說明
	 * @param isShowLegend			是否要顯示圖例
	 * @param legends	 			圖例標籤
	 * @param xAxisLabelPaint		xAxisLabel paint
	 * @param xAxisUnitDescPaint	X軸裡單位說明文字的Paint object
	 * 
	 * @return	y-axis interval pixels of two yAxisLabel unit
	 */
	public float calYAxisIntervalForTwoYAxisLabelUnit(float canvasWidth,float canvasHeight,
											  	  	  int yAxisLabelAmount,boolean isShowXUnitDesc,
											  	  	  boolean isShowLegend,String[] legends,
											  	  	  Paint xAxisLabelPaint,Paint xAxisUnitDescPaint){
		return (canvasHeight - calXAxisLabelHeightWithTopAndBottomPad(xAxisLabelPaint) * 2 - calXAxisUnitDescHeightWithTopAndBottomPad(isShowXUnitDesc,xAxisUnitDescPaint) -
				calTotalLegendsHeightWithTopAndBottomPad(isShowLegend,legends,canvasWidth)) / (yAxisLabelAmount - 1);
	}	
	
	/**
	 * Calculate x-axis interval pixels of two xAxisLabel unit
	 * 
	 * @param canvasWidth			Canvas width
	 * @param isShowYUnitDesc		是否要顯示Y軸的單位說明
	 * @param maxYAxisLabel			所有Y軸標籤裡的最大值
	 * @param xAxisLabelAmount		X軸標籤總個數
	 * @param maxXAxisLabel			所有X軸標籤裡的最大值 
	 * @param yAxisLabelPaint		yAxisLabel paint
	 * @param yAxisUnitDescPaint	Y軸裡單位說明文字的Paint object
	 * 
	 * @return	x-axis interval pixels of two xAxisLabel unit
	 */
	public float calXAxisIntervalForTwoXAxisLabelUnit(float canvasWidth,boolean isShowYUnitDesc,String maxYAxisLabel,int xAxisLabelAmount,
											  	  String maxXAxisLabel,Paint yAxisLabelPaint,Paint yAxisUnitDescPaint){
		return (canvasWidth - calYAxisUnitDescHeightWithTopAndBottomPad(isShowYUnitDesc,yAxisUnitDescPaint) -
				calYAxisLabelWidthWithLeftAndRightPad(maxYAxisLabel,yAxisLabelPaint) - 
				calXAxisLabelOrYAxisLabelWidth(maxXAxisLabel) * 0.5F - textPadding) / ((xAxisLabelAmount - 1) + 0.5F);
	}
	
	/**
	 * 計算顯示Tip時的背景區塊空間大小
	 * 
	 * @param canvasWidth	Canvas width
	 * @param chartData		Chart Data
	 * @param tipTextPaint	折線點被點擊時，提示文字所用到的Paint object
	 * 
	 * @return	顯示Tip時的背景區塊空間大小
	 */
	public Rect calTipRect(float canvasWidth,AbstractChartData<?> chartData,Paint tipTextPaint){
		float tipTextWidthWithLeftAndRightPad = calTextWidth(chartData.getTipText(), tipTextPaint) + tipTextPadding * 2;
		float tipTextHeightWithTopAndBottomPad = calTextHeight(tipTextPaint) + tipTextPadding * 2;
		int leftOfTipRect = 0;
		int topOfTipRect = 0;
		int rightOfTipRect = 0;
		int bottomOfTipRect = 0;
		
		if((chartData.getXPosition() + tipTextWidthWithLeftAndRightPad / 2 <= canvasWidth) &&
		   (chartData.getXPosition() - tipTextWidthWithLeftAndRightPad / 2 >= 0)){
			leftOfTipRect = (int)(chartData.getXPosition() - tipTextWidthWithLeftAndRightPad / 2);
			rightOfTipRect = (int)(leftOfTipRect + tipTextWidthWithLeftAndRightPad);
		}
		else if(chartData.getXPosition() - tipTextWidthWithLeftAndRightPad / 2 < 0){
			leftOfTipRect = 0;
			rightOfTipRect = (int)(leftOfTipRect + tipTextWidthWithLeftAndRightPad);
		}
		else{
			rightOfTipRect = (int)canvasWidth;
			leftOfTipRect = (int)(rightOfTipRect - tipTextWidthWithLeftAndRightPad); 
		}

		if(chartData.getYPosition() - (2 * tipTextHeightWithTopAndBottomPad + 2 * dataSeriesDotRadias) <= 0){
			topOfTipRect = (int)(chartData.getYPosition() +  2 * dataSeriesDotRadias);
			bottomOfTipRect = (int)(topOfTipRect +  2 * tipTextHeightWithTopAndBottomPad);
		}
		else{
			bottomOfTipRect = (int)(chartData.getYPosition() - 2 * dataSeriesDotRadias);
			topOfTipRect = (int)(bottomOfTipRect - 2 * tipTextHeightWithTopAndBottomPad); 
		}				
		
		return new Rect(leftOfTipRect, topOfTipRect, rightOfTipRect, bottomOfTipRect);
	}
}
